package com.sso.utils;

import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.nio.charset.Charset;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

/**
 * date: 2019/07/26
 * writed by yangtingting
 * @author HP
 */
@Slf4j
public class ZipUtil {

	/**
	 * zip解压
	 *
	 * @param srcFile     zip源文件
	 * @param destDirPath 解压后的目标文件夹
	 * @throws RuntimeException 解压失败会抛出运行时异常
	 */

	public static void unZip(File srcFile, String destDirPath) throws RuntimeException {
		long start = System.currentTimeMillis();
		// 判断源文件是否存在
		if (!srcFile.exists()) {
			throw new RuntimeException(srcFile.getPath() + "所指文件不存在");
		}
		// 开始解压
		ZipFile zipFile = null;
		try {
			zipFile = new ZipFile(srcFile);
			Enumeration<?> entries = zipFile.entries();
			while (entries.hasMoreElements()) {
				ZipEntry entry = (ZipEntry) entries.nextElement();
				System.out.println("解压" + entry.getName());
				// 如果是文件夹，就创建个文件夹
				if (entry.isDirectory()) {
					String dirPath = destDirPath + "/" + entry.getName();
					File dir = new File(dirPath);
					dir.mkdirs();
				} else {
					// 如果是文件，就先创建一个文件，然后用io流把内容copy过去
					File targetFile = new File(destDirPath + "/" + entry.getName());
					// 保证这个文件的父文件夹必须要存在
					if (!targetFile.getParentFile().exists()) {
						targetFile.getParentFile().mkdirs();
					}
					targetFile.createNewFile();
					// 将压缩文件内容写入到这个文件中
					InputStream is = zipFile.getInputStream(entry);
					FileOutputStream fos = new FileOutputStream(targetFile);
					int len;
					byte[] buf = new byte[1024];
					while ((len = is.read(buf)) != -1) {
						fos.write(buf, 0, len);
					}
					// 关流顺序，先打开的后关闭
					fos.close();
					is.close();
				}
			}
			long end = System.currentTimeMillis();
			System.out.println("解压完成，耗时：" + (end - start) + " ms");
		} catch (Exception e) {
			throw new RuntimeException("unzip error from ZipUtils", e);
		} finally {
			if (zipFile != null) {
				try {
					zipFile.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

	/**
	 * 	解压超大Zip文件
	 * @param zipFile zip文件位置
	 * @throws IOException
	 */
	public static void deCompress(String zipFile) throws IOException{
		long start = System.currentTimeMillis();
		File zfile = new File(zipFile);
		log.info("开始解压Maps的.zip文件{}",zfile.getPath());
		String parent = zfile.getParent()+"/"+zfile.getName().replace(".zip","/");
		File file = new File(parent);
		file.mkdir();
		System.out.println(parent);
		Charset charset = Charset.forName("GBK");
		ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFile),charset);
		ZipEntry entry = null;
		BufferedOutputStream bos = null;
		while ((entry = zis.getNextEntry())!=null){
			File filePath = new File(parent+entry.getName());
			if(entry.isDirectory()){
				if(!filePath.exists()){
					filePath.mkdir();
					System.out.println(filePath.getPath());
				}
			}else {
				if (filePath.exists()){
					filePath.delete();
				}
				FileOutputStream fos = new FileOutputStream(parent+entry.getName());
				bos = new BufferedOutputStream(fos);

				byte[] buf = new byte[10*1024*1024];
				int len;
				while ((len = zis.read(buf))!=-1){
					bos.write(buf,0,len);
				}
				zis.closeEntry();
				bos.close();
			}
		}
		long end = System.currentTimeMillis();
		log.info("解压Maps的.zip文件完成，耗时：" + (end - start) + " ms");
	}



	/**
	 * 压缩文件
	 *
	 * @param sourceFilePath 源文件路径
	 * @param zipFilePath    压缩后文件存储路径
	 * @param zipFilename    压缩文件名
	 */
	public static void compressToZip(String sourceFilePath, String zipFilePath, String zipFilename) {
		File sourceFile = new File(sourceFilePath);
		File zipPath = new File(zipFilePath);
		if (!zipPath.exists()) {
			zipPath.mkdirs();
		}
		File zipFile = new File(zipPath + File.separator + zipFilename);
		try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFile))) {
			writeZip(sourceFile, "", zos);
			//文件压缩完成后，删除被压缩文件
			boolean flag = deleteDir(sourceFile);
			log.info("删除被压缩文件[" + sourceFile + "]标志：{}", flag);
		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException(e.getMessage(), e.getCause());
		}
	}



	/**
	 * 遍历所有文件，压缩
	 *
	 * @param file       源文件目录
	 * @param parentPath 压缩文件目录
	 * @param zos        文件流
	 */
	public static void writeZip(File file, String parentPath, ZipOutputStream zos) {
		if (file.isDirectory()) {
			//目录
			parentPath += file.getName() + File.separator;
			File[] files = file.listFiles();
			for (File f : files) {
				writeZip(f, parentPath, zos);
			}
		} else {
			//文件
			try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file))) {
				//指定zip文件夹
				ZipEntry zipEntry = new ZipEntry(parentPath + file.getName());
				zos.putNextEntry(zipEntry);
				int len;
				byte[] buffer = new byte[1024 * 10];
				while ((len = bis.read(buffer, 0, buffer.length)) != -1) {
					zos.write(buffer, 0, len);
					zos.flush();
				}
			} catch (Exception e) {
				e.printStackTrace();
				throw new RuntimeException(e.getMessage(), e.getCause());
			}
		}
	}

		/**
		 * 删除文件夹
		 *
		 * @param dir
		 * @return
		 */
		public static boolean deleteDir (File dir){
			if (dir.isDirectory()) {
				String[] children = dir.list();
				for (int i = 0; i < children.length; i++) {
					boolean success = deleteDir(new File(dir, children[i]));
					if (!success) {
						return false;
					}
				}
			}
			//删除空文件夹
			return dir.delete();
		}


		public static void main (String[]args){
			try {
//				compressToZip("C:\\Users\\HP\\Desktop\\111", "C:\\Users\\HP\\Desktop","111.zip");
//			ZipUncompress("C:\\Users\\HP\\Desktop\\aaa.zip","C:\\Users\\HP\\Desktop\\ccc");
				unZip(new File("C:\\Users\\HP\\Desktop\\111.zip"), "C:\\Users\\HP\\Desktop");
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

